package Server.domain;

import Server.domain.threads.BomberManClientThread;
import Server.gui.BomberManServerGUI;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

/**
 *
 * @author Michael Heughebaert <michael.heughebaert.r2449@student.hogent.be>
 */
public class BomberManChatServer {
    
    public static final int MAX_CLIENTS = 4;
    private int no_clients;
    private int clientId;
    private ArrayList<BomberManClientThread> clients;
    private BomberManServerGUI bmGui;
    private SimpleDateFormat sdf;
    private int tcpPort;
    private boolean running;
    private boolean maxClientsReached;

    public BomberManChatServer(int tcpPort, BomberManServerGUI bmGui) {
        this.tcpPort = tcpPort;
        this.bmGui = bmGui;
        sdf = new SimpleDateFormat("HH:mm:ss");
        clients = new ArrayList<>();
    }
    
    public BomberManChatServer(int port) {
	        this(port, null);
     }

    //Method to handle server start
    public void start() {
        running = true;

        try {
            ServerSocket serverSocket = new ServerSocket(tcpPort);

            while (running) {
                if (!running) {
                    break;
                }
               
                display("Server waiting for Clients on port " + tcpPort + ".");
                Socket socket = serverSocket.accept();

                

                if (no_clients < MAX_CLIENTS) {
                    BomberManClientThread clThread = new BomberManClientThread(this, socket, clientId);
                    clients.add(clThread);
                    clThread.start();
                    display("You have joined the Bomberman Chat Server");
                    no_clients++;
                    clientId++;
                    
                } else {
                     display("SERVER FULL (4/4): Client tried to connect");
                     setMaxClientsReached(true);
                     
                }
                
            }

            try {
                serverSocket.close();

                for (int i = 0; i < clients.size(); ++i) {
                    BomberManClientThread clThread = clients.get(i);
                    try {
                    clThread.getiStream().close();
	            clThread.getoStream().close();
	            clThread.getSocket().close();
                    }
                    catch(IOException ioE) {
	            }
                }
            } catch (Exception e) {
                display("Exception closing the server and clients: " + e);
            }
        } catch (IOException e) {
           String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
	   display(msg);
        }
    }

    //Method to handle server stop
    public void stop() {
        running = false;

        display("The Chat server is stopping...");

        try {
            Socket s = new Socket("localhost", tcpPort);
        } catch (Exception e) {
        }
    }
    
       public boolean isRunning() {
        return running;
    }
       
        public void setRunning(boolean running) {
        this.running = running;
    }

       public void display(String msg) {
	        String time = sdf.format(new Date()) + " " + msg;
	        if(bmGui == null)
	            System.out.println(time);
	        else
	            bmGui.appendEvent(time + "\n");
	    }
        
        public synchronized void broadcast(String message) {
	        // add HH:mm:ss and \n to the message
	        String time = sdf.format(new Date());
	        String messageLf = time + " " + message + "\n";
	        // display message on console or GUI
	        if(bmGui == null)
	            System.out.print(messageLf);
	        else
	            bmGui.appendRoom(messageLf);     // append in the room window
	         
	        // we loop in reverse order in case we would have to remove a Client
	        // because it has disconnected
	        for(int i = clients.size(); --i >= 0;) {
	            BomberManClientThread ct = clients.get(i);
	            // try to write to the Client if it fails remove it from the list
	            if(!ct.writeMsg(messageLf)) {
	                clients.remove(i);
	                display("Disconnected Client " + ct.getUsername() + " removed from list.");
	            }
	        }
	    }
        
        public synchronized void remove(int id) {
	        // scan the array list until we found the Id
	        for(int i = 0; i < clients.size(); ++i) {
	            BomberManClientThread ct = clients.get(i);
	            // found it
	            if(ct.getClientId() == id) {
	                clients.remove(i);
	                return;
	            }
	        }
	    }
        
        public static void main(String[] args) {
	        // start server on port 7777 unless a PortNumber is specified
	        int portNumber = 7777;
	        switch(args.length) {
	            case 1:
	                try {
	                    portNumber = Integer.parseInt(args[0]);
	                }
	                catch(Exception e) {
	                    System.out.println("Invalid port number.");
	                    System.out.println("Usage is: > java Server [portNumber]");
	                    return;
	                }
	            case 0:
	                break;
	            default:
	                System.out.println("Usage is: > java Server [portNumber]");
	                return;
	                 
	        }
	        // create a server object and start it
	        BomberManChatServer server = new BomberManChatServer(portNumber);
	        server.start();
	    }  

    public boolean isMaxClientsReached() {
        return maxClientsReached;
    }

    public void setMaxClientsReached(boolean maxClientsReached) {
        this.maxClientsReached = maxClientsReached;
    }
        
        
}